package com.york.tinyrpc.protoss.server.tcp.wrapper;

import com.york.tinyrpc.protoss.constant.TinyRpcProtocolConstants;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.parsetools.RecordParser;

/**
 * 装饰器模式
 * 增强Handler<Buffer>能力
 * 目的是引入RecordParser解决粘包半包问题
 */
public class TcpBufferHandlerWrapper implements Handler<Buffer> {

    /**
     * 封装RecordParser处理半包粘包
     * 核心就是parser可以完美获取指定的数据
     */
    private final RecordParser parser;

    /**
     * 构造器初始化parser
     *
     * @param bufferHandler
     */
    public TcpBufferHandlerWrapper(Handler<Buffer> bufferHandler) {
        parser = initRecordParser(bufferHandler);
    }

    /**
     * 初始化parser
     *
     * @param bufferHandler
     * @return
     */
    private RecordParser initRecordParser(Handler<Buffer> bufferHandler) {
        // 构造 parser,根据我们对消息结构的设置，消息头是定长17个字节，消息体的长度由消息头中的bodyLength决定
        RecordParser parser = RecordParser.newFixed(TinyRpcProtocolConstants.MESSAGE_HEADER_LENGTH);

        parser.setOutput(new Handler<Buffer>() {
            // 初始化
            int bodyLength = -1;

            // 一次完整的读取（头 + 体）
            Buffer resultBuffer = Buffer.buffer();

            /**
             * 增强处理逻辑
             * @param buffer
             */
            @Override
            public void handle(Buffer buffer) {
                if (-1 == bodyLength) {
                    // -1 说明bodyLength还未读取到有效值
                    // 读取bodyLength，根据消息结构定义，最后一个字段是bodyLength，在第13个字节起int类型
                    bodyLength = buffer.getInt(13);
                    parser.fixedSizeMode(bodyLength);
                    // 写入头信息到结果
                    resultBuffer.appendBuffer(buffer);
                } else {
                    // 已经读取到bodyLength有效值，写入体信息到结果
                    resultBuffer.appendBuffer(buffer);
                    // 已拼接为完整 Buffer，执行处理
                    bufferHandler.handle(resultBuffer);
                    // 重置一轮
                    parser.fixedSizeMode(TinyRpcProtocolConstants.MESSAGE_HEADER_LENGTH);
                    bodyLength = -1;
                    resultBuffer = Buffer.buffer();
                }
            }
        });

        return parser;
    }

    @Override
    public void handle(Buffer buffer) {
        parser.handle(buffer);
    }
}
